package com.itheima.service.impl;

import com.itheima.domain.dto.VoucherOrderMessageDTO;
import com.itheima.domain.entity.SeckillVoucher;
import com.itheima.domain.entity.VoucherOrder;
import com.itheima.domain.vo.Result;
import com.itheima.mapper.VoucherOrderMapper;
import com.itheima.service.ISeckillVoucherService;
import com.itheima.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.utils.RedisMakeIds;
import com.itheima.utils.ThreadUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 坤哥
 * @since 2025-10-06
 */
@Service
@Slf4j
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {
    @Resource
    private RedisMakeIds redisMakeIds;
    @Resource
    private ISeckillVoucherService seckillVoucherService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RabbitTemplate rabbitTemplate;

    //编写lua脚本
    private static final DefaultRedisScript<Long> LUA_SECKILL_SCRIPT;
    static {
        LUA_SECKILL_SCRIPT = new DefaultRedisScript<>();
        LUA_SECKILL_SCRIPT.setLocation(new ClassPathResource("secKill.lua"));
        LUA_SECKILL_SCRIPT.setResultType(Long.class);
    }

    /**
     * 抢购优惠券
     */
    @Override
    public Result seckillVoucher(Long voucherId) {
        //手动把秒杀优惠券的库存存入redis
        //判断是否在购买的时间范围内
        SeckillVoucher seckillVoucher = seckillVoucherService.lambdaQuery().eq(SeckillVoucher::getVoucherId, voucherId).one();
        LocalDateTime beginTime = seckillVoucher.getBeginTime();
        LocalDateTime endTime = seckillVoucher.getEndTime();
        //如果不在时间范围内，返回提示信息
        if(beginTime.isAfter(LocalDateTime.now())){
            return Result.fail("活动未开始");
        }
        if(endTime.isBefore(LocalDateTime.now())){
            return Result.fail("活动已结束");
        }
        //在有效时间范围内，基于lua脚本一气呵成查询redis库存和把优惠券订单放入消息队列，并返回提示信息
        //获取用户id
        Long userId = ThreadUtil.get().getUserId();
        //获取订单id
        long orderId = redisMakeIds.makeIds("order");
        //执行lua脚本
        long lua = stringRedisTemplate.execute(
                LUA_SECKILL_SCRIPT,
                Collections.emptyList(),
                userId.toString(), voucherId.toString()
        );
        //根据返回值判断下一步操作
        //若返回1则说明库存不足
        if(lua == 1){
            return Result.fail("库存不足");
        }
        //若返回2则说明用户已经购买过了
        if(lua == 2){
            return Result.fail("您已购买该商品");
        }
        //若返回0则指派rabbitmq去确认消息队列中的订单，然后把创建的订单存入数据库
        VoucherOrderMessageDTO message = new VoucherOrderMessageDTO(orderId,userId,voucherId);
        //把订单信息发送给普通的消息队列去创建订单并更新库存
        rabbitTemplate.convertAndSend("exchange.direct","queue.kun",message);
        return Result.ok(orderId);
    }
    /**
     * 创建订单，扣减库存
     */
    @Override
    @Transactional
    public void createOrder(VoucherOrderMessageDTO orderMessage) {
        //创建订单
        VoucherOrder voucherOrder = VoucherOrder.builder()
                .userId(orderMessage.getUserId())
                .voucherId(orderMessage.getVoucherId())
                .payType(2)
                .status(1)
                .build();
        voucherOrder.setId(orderMessage.getId());
        save(voucherOrder);
        //扣减库存
        seckillVoucherService.lambdaUpdate()
                .eq(SeckillVoucher::getVoucherId,orderMessage.getVoucherId())
                .setSql("stock = stock -1")
                .update();
    }
}
